/**
 * 
 */
package kevin.study.zephyr.domain.dao.soda;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import kevin.study.zephyr.domain.soda.Constraint;
import kevin.study.zephyr.exceptions.ConstraintConditionWrongException;


/**
 * @author Kevin.Huang
 * @date 2007-9-30
 */
public class ZConstraint implements Constraint {

	/**
	 * constant defination : value of "=" sql operator
	 */
	public static final String EQUAL = "equal";

	/**
	 * constant defination: value of "!=" sql operator
	 */
	public static final String NOT = "not";

	/**
	 * constant defination: value of ">=" sql operator
	 */
	public static final String GREATER = "greater";

	/**
	 * constant defination: value of "<=" sql operator
	 */
	public static final String SMALLER = "smaller";

	/**
	 * constant defination: value of "between" sql operator
	 */
	public static final String CONTAINS = "contains";

	/**
	 * constant defination: value of "like" sql operator
	 */
	public static final String LIKE = "like";

	/**
	 * constant defination: value of "startsWith" sql operator
	 */
	public static final String STARTSWITH_TRUE = "startsWith:true";

	/**
	 * constant defination: value of "startsWith" sql operator
	 */
	public static final String STARTSWITH_FALSE = "startsWith:false";

	/**
	 * constant defination: value of "endsWith" sql operator
	 */
	public static final String ENDSWITH_TRUE = "endsWith:true";

	/**
	 * constant defination: value of "endsWith" sql operator
	 */
	public static final String ENDSWITH_FALSE = "endsWith:false";

	/**
	 * 此约束所在的Query节点
	 */
	private ZQuery query;

	/**
	 * 次约束的基准值
	 */
	private Object value;

	private List< ZConstraintLink > zConstraintLinks = new ArrayList< ZConstraintLink >();

	/**
	 * 关联的约束
	 */
	private Collection< String > conditions = new ArrayList< String >();

	protected ZConstraint(ZQuery query, Object value) {
		this.query = query;
		this.value = value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#and(kevin.study.zephyr.domain.soda.Constraint)
	 */
	public Constraint and(Constraint with) {
		zConstraintLinks.add(new ZConstraintLink(ZConstraintLink.TYPE_AND, (ZConstraint) with));
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#contains()
	 */
	public Constraint contains() {
		String[] c = {NOT };
		if (conflictOnly(c)) {
			throw new ConstraintConditionWrongException("contains  only can with not!");
		}
		this.conditions.add(CONTAINS);
		return this;
	}

	public Constraint endsWith(boolean caseSensitive) {
		String[] c = {NOT };
		if (conflictOnly(c)) {
			throw new ConstraintConditionWrongException("endsWith  only can with not!");
		}
		if (caseSensitive) {
			this.conditions.add(ENDSWITH_TRUE);
		} else {
			this.conditions.add(ENDSWITH_FALSE);
		}
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#equal()
	 */
	public Constraint equal() {
		String[] c = {EQUAL, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE, STARTSWITH_TRUE };
		if (conflictExist(c)) {
			throw new ConstraintConditionWrongException(
					"equal can't with contains , endsWith, startsWith, like or himself!");
		}
		this.conditions.add(EQUAL);
		return this;
	}

	/**
	 * @return the conditions
	 */
	public Collection< String > getConditions() {
		return conditions;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#getObject()
	 */
	public Object getObject() {
		return this.value;
	}

	/**
	 * @return the query
	 */
	public ZQuery getQuery() {
		return query;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#greater()
	 */
	public Constraint greater() {
		String[] c = {GREATER, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE,
						STARTSWITH_TRUE };
		if (conflictExist(c)) {
			throw new ConstraintConditionWrongException(
					"greater can't with contains , endsWith, startsWith, like or himself!");
		}
		this.conditions.add(GREATER);
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#like()
	 */
	public Constraint like() {
		String[] c = {NOT };
		if (conflictOnly(c)) {
			throw new ConstraintConditionWrongException("like  only can with not!");
		}
		this.conditions.add(LIKE);
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#not()
	 */
	public Constraint not() {
		if (conditions.contains(NOT)) {
			throw new ConstraintConditionWrongException("not already exist!");
		}
		this.conditions.add(NOT);
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#or(kevin.study.zephyr.domain.soda.Constraint)
	 */
	public Constraint or(Constraint with) {
		zConstraintLinks.add(new ZConstraintLink(ZConstraintLink.TYPE_OR, (ZConstraint) with));
		return this;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see kevin.study.zephyr.domain.soda.Constraint#smaller()
	 */
	public Constraint smaller() {
		String[] c = {SMALLER, LIKE, CONTAINS, ENDSWITH_TRUE, ENDSWITH_FALSE, STARTSWITH_FALSE,
						STARTSWITH_TRUE };
		if (conflictExist(c)) {
			throw new ConstraintConditionWrongException(
					"Smaller can't with contains ,endsWith, startsWith, like or himself!");
		}
		this.conditions.add(SMALLER);
		return this;
	}

	public Constraint startsWith(boolean caseSensitive) {
		String[] c = {NOT };
		if (conflictOnly(c)) {
			throw new ConstraintConditionWrongException("endsWith  only can with not!");
		}
		if (caseSensitive) {
			this.conditions.add(STARTSWITH_TRUE);
		} else {
			this.conditions.add(STARTSWITH_FALSE);
		}
		return this;
	}

	private boolean conflictExist(String[] conditionStrings) {
		for (String conditionString : conditionStrings) {
			if (conditions.contains(conditionString)) {
				return true;
			}
		}
		return false;
	}

	private boolean conflictOnly(String[] conditionStrings) {
		for (String existCondition : conditions) {
			for (String conditionString : conditionStrings) {
				if (existCondition.equals(conditionString)) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @return the zConstraintLinks
	 */
	public List< ZConstraintLink > getZConstraintLinks() {
		return zConstraintLinks;
	}
}
